package install

import (
	"fmt"
	"gitee.com/yangguoliang001/go-gin-vue3/common"
	"gitee.com/yangguoliang001/go-gin-vue3/config"
	"gitee.com/yangguoliang001/go-gin-vue3/db/tablesqls"
	"gitee.com/yangguoliang001/go-gin-vue3/pkg/response"
	"gitee.com/yangguoliang001/go-gin-vue3/util/code"
	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis/v7"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"

	"github.com/spf13/cast"
	"github.com/spf13/viper"
	"net/url"
	"os"
	"runtime"
)

type initExecuteReq struct {
	//Language  string `form:"language"`
	RedisAddr string `form:"redisAddr"`
	RedisPass string `form:"redisPass"`
	RedisDb   int    `form:"redisDb"`

	MysqlAddr string `form:"mysqlAddr"`
	MysqlUser string `form:"mysqlUser"`
	MysqlPass string `form:"mysqlPass"`
	MysqlName string `form:"mysqlName"`
}

// Execute  测试初始化配置
// @Summary 测试初始化配置
// @Description 初始化数据库等配置、mock
// @Tags API.install
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Router /install/execute [post]
// @Param redisAddr formData string true "redis 地址" default(127.0.0.1:6379)
// @Param redisPass formData string false "redis 密码" default()
// @Param redisDb formData int true "redis 数据库" default(0)
// @Param mysqlAddr formData string true "mysql 地址" default(127.0.0.1:3306)
// @Param mysqlName formData string true "mysql 名称" default(go_gin_api)
// @Param mysqlUser formData string true "mysql 用户名" default(root)
// @Param mysqlPass formData string true "mysql 密码" default(123456)
// Success 200 {object} TInstall
func (i *installController) Execute() gin.HandlerFunc {
	return func(c *gin.Context) {
		req := new(initExecuteReq)
		// 数据绑定错误
		if err := c.ShouldBind(&req); err != nil {
			//c.AbortWithError(http.StatusBadRequest, err)
			response.Fail(c, code.ParamBindError, code.Text(code.ParamBindError), gin.H{"realErr": err})
			return
		}

		fmt.Printf("传入配置：%#v \n", req)
		//	验证go version
		versionStr := runtime.Version()
		version := cast.ToFloat32(versionStr[2:6])
		if version < config.MinGoVersion {
			//fn := myerror.Error(http.StatusBadRequest, code.GoVersionError, code.Text(code.GoVersionError))
			response.Fail(c, code.GoVersionError, code.Text(code.GoVersionError), gin.H{})
			return
		}

		//	验证redis配置
		cfg := common.Get()
		var outPutString = ""
		redisClient := redis.NewClient(&redis.Options{
			Addr:         req.RedisAddr,
			Password:     req.RedisPass,
			DB:           req.RedisDb,
			MaxRetries:   cfg.Redis.MaxRetries, // 最大重试次数
			PoolSize:     cfg.Redis.PoolSize,   // websocket 最大链接数
			MinIdleConns: cfg.Redis.MinIdleConns,
		})
		if err := redisClient.Ping().Err(); err != nil {
			response.Fail(c, code.RedisConnectError, code.Text(code.RedisConnectError), gin.H{"realErr": err})
			return
		}

		outPutString += "已检测到 Redis 配置可用。\n"

		// 验证 mysql 配置
		dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=%s&parseTime=True&loc=%s",
			req.MysqlUser,
			req.MysqlPass,
			req.MysqlAddr,
			req.MysqlName,
			cfg.MySQL.Charset,
			url.QueryEscape(cfg.MySQL.Loc),
		)
		db, err := gorm.Open(mysql.Open(dsn))
		if err != nil {
			response.Fail(c, code.MySQLConnectError, code.Text(code.MySQLConnectError), gin.H{"realErr": err})
			return
		}
		//defer

		outPutString += "已检测到 mysql 配置可用 \n"

		// 重新保存 数据库配置
		viper.Set("redis.addr", req.RedisAddr)
		viper.Set("redis.pass", req.RedisPass)
		viper.Set("redis.db", req.RedisDb)

		viper.Set("mysql.addr", req.MysqlAddr)
		viper.Set("mysql.name", req.MysqlName)
		viper.Set("mysql.user", req.MysqlUser)
		viper.Set("mysql.pass", req.MysqlPass)

		if err := viper.WriteConfig(); err != nil {
			response.Fail(c, code.WriteConfigError, code.Text(code.WriteConfigError), gin.H{"realErr": err})
			return
		}
		outPutString += "配置 Redis、Mysql 成功 \n"
		//outPutString += "配置 Redis、Mysql 成功。\n"
		fmt.Printf("测试结果： %s", outPutString)

		// 初始化数据库和mock
		installTableList := initTableList()

		for k, v := range installTableList {
			if v["table_sql"] != "" {
				// 初始化表结构
				if err = db.Exec(v["table_sql"]).Error; err != nil {
					response.Fail(c, code.MySQLExecError, code.Text(code.MySQLExecError), gin.H{"realErr": err})
					return
				}

				outPutString += "初始化 Mysql 数据表：" + k + "成功。 \n"

				//	初始化默认数据
				if v["table_data_sql"] != "" {
					if err = db.Exec(v["table_data_sql"]).Error; err != nil {
						response.Fail(c, code.MySQLExecError, code.Text(code.MySQLExecError), gin.H{"realErr": err})
						return
					}
					outPutString += "初始化 Mysql 数据表：" + k + "默认数据成功。 \n"
				}
			}
		}

		// 创建成功标识
		f, err := os.Create(config.ProjectInstallMark)
		fmt.Println("install execute 创建成功标识: " + err.Error())
		if err != nil {
			response.Fail(c, code.MySQLExecError, code.Text(code.MySQLExecError), gin.H{"realErr": err})
			return
		}
		defer f.Close()

		// 成功
		response.Success(c, "配置成功", gin.H{
			"outPutString": outPutString,
		})
	}
}

// 初始化mysql数据
func initTableList() map[string]map[string]string {
	return map[string]map[string]string{
		"authorized": {
			"table_sql":      tablesqls.CreateAuthorizedTableSql(),
			"table_data_sql": tablesqls.CreateAuthorizedTableDataSql(),
		},
		"authorized_api": {
			"table_sql":      tablesqls.CreateAuthorizedAPITableSql(),
			"table_data_sql": tablesqls.CreateAuthorizedAPITableDataSql(),
		},
		"admin": {
			"table_sql":      tablesqls.CreateAdminTableSql(),
			"table_data_sql": tablesqls.CreateAdminTableDataSql(),
		},
		"admin_menu": {
			"table_sql":      tablesqls.CreateAdminMenuTableSql(),
			"table_data_sql": tablesqls.CreateAdminMenuTableDataSql(),
		},
		"menu": {
			"table_sql":      tablesqls.CreateMenuTableSql(),
			"table_data_sql": tablesqls.CreateMenuTableDataSql(),
		},
		"menu_action": {
			"table_sql":      tablesqls.CreateMenuActionTableSql(),
			"table_data_sql": tablesqls.CreateMenuActionTableDataSql(),
		},
		"cron_task": {
			"table_sql":      tablesqls.CreateCronTaskTableSql(),
			"table_data_sql": "",
		},
	}
}
